﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using ResourceBlender.Core;

namespace ResourceBlender.DAL.Import
{
    public class PoResourceImporter
    {
        /// <summary>
        /// Imports from GNU PO files.
        /// </summary>
        /// <param name="files">The files to import.</param>
        /// <param name="logHandler">The log handler.</param>
        /// <param name="appendLanguages"><c>true</c> if languages not currently used by the application should be added, otherwise false.</param>
        public static void Import(StatusMessage.StatusChangedEventHandler log, Dictionary<string, string> files, RBApplication application, bool appendLanguages)
        {
            Dictionary<string, Dictionary<string, Dictionary<string, string>>> bundles = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>(); // <BundleName, <msgId<language, translation>>>
            Dictionary<string, Dictionary<string, POMetaData>> elementData = new Dictionary<string, Dictionary<string, POMetaData>>(); // <BundleName, <ElementName, Meta-data>>
            string bundleName, language;
            int splitter;
            log(new StatusMessage(I18nUtils.GetString("UIStrings", "ParsingBundles"), StatusMessage.StatusMessageType.Status));
            Regex rgxUntranslatedString = new Regex("msgid \"(.*)\""),
                  rgxTranslatedString = new Regex("msgstr \"(.*)\""),
                  rgxUntranslatedPlural = new Regex("msgid_plural \"(.*)\""),
                  rgxTranslatedPlural = new Regex("msgstr\\[(\\d)\\] \"(.*)\""),
                  rgxContext = new Regex("msgctxt \".*\"");
            List<string> newLanguages = new List<string>();
            foreach (KeyValuePair<string, string> file in files)
            { // <filename, UTF8 contents>
                if (file.Value.Length == 0)
                {
                    continue;
                }
                string fileNameNoExt = Path.GetFileNameWithoutExtension(file.Key);
                splitter = file.Key.IndexOf('\\');
                if (splitter <= 0)
                { // no directory means no bundle, create a new bundle
                    //todo: 1 - check this works with subdirs
                    bundleName = DateTime.Now.ToString("HH:mm") + "-" + new Random().Next(100);
                }
                else
                {
                    bundleName = file.Key.Substring(0, splitter);
                }
                language = fileNameNoExt;
                if (appendLanguages && !application.Languages.Contains(language) && !newLanguages.Contains(language))
                {
                    try
                    {
                        CultureInfo info = new CultureInfo(language); // is it a language or a randomly named file
                        newLanguages.Add(language);
                    }
                    catch
                    {
                        // language not valid. If it was a custom code, the user can add it manually.
                    }
                }
                if (!bundles.ContainsKey(bundleName))
                {
                    bundles.Add(bundleName, new Dictionary<string, Dictionary<string, string>>());
                    elementData.Add(bundleName, new Dictionary<string, POMetaData>());
                }
                string[] entries = file.Value.Split(new string[] { "\n\n" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string entry in entries)
                {
                    string[] lines = entry.Split('\n');
                    try
                    {
                        POMetaData data = new POMetaData();
                        string line;
                        StringBuilder translatorComments = null;
                        for (int i = 0; i < lines.Length; i++)
                        {
                            line = lines[i].Trim();
                            if (line.Length > 4)
                            {
                                switch (line.Substring(0, 2))
                                {
                                    case "# ":
                                        if (translatorComments == null)
                                        {
                                            translatorComments = new StringBuilder();
                                        }
                                        translatorComments.AppendLine(line.Substring(2).Trim());
                                        break;
                                    case "#.":
                                        data.ExtractedComments.Add(line.Substring(2).Trim());
                                        break;
                                    case "#:":
                                        data.References.Add(line.Substring(2).Trim());
                                        break;
                                    case "#,":
                                        data.Flags.Add(line.Substring(2).Trim());
                                        break;
                                    default:
                                        if (line.Length > 7)
                                        { // min is 'msgid ""'
                                            int j;
                                            if (line.StartsWith("msgid") && line.Length >= 8)
                                            {
                                                Match matchUntranslated = rgxUntranslatedString.Match(line);
                                                if (matchUntranslated.Success && matchUntranslated.Groups[1].Value.Length == 0)
                                                { // line is msgid "" -  multiline string, move to the next line to start reading
                                                    StringBuilder multiLine = new StringBuilder();
                                                    for (j = i + 1; j < lines.Length; j++)
                                                    {
                                                        string nextLine = lines[j].Trim();
                                                        if (nextLine.Length < 2 || nextLine[0] != '"')
                                                        { // either an unexpected char or anything but a quote means the end of the multi-line string
                                                            break;
                                                        }
                                                        else if (line.Length > 3)
                                                        { // A line could contain just "", but it should be skipped if so
                                                            multiLine.Append(nextLine.Substring(1, nextLine.Length - 2));
                                                        }
                                                    }
                                                    if (multiLine.Length > 0)
                                                    {
                                                        data.UntranslatedString = multiLine.ToString();
                                                        i = j - 1;
                                                    }
                                                }
                                                else if (line.Length >= 9)
                                                { // Must be at least msgid "x"
                                                    Match matchPluralUntranslated = rgxUntranslatedPlural.Match(line);
                                                    if (matchPluralUntranslated.Success)
                                                    {
                                                        data.UntranslatedPlural = matchPluralUntranslated.Groups[1].Value;
                                                    }
                                                    else
                                                    {
                                                        data.UntranslatedString = matchUntranslated.Groups[1].Value;
                                                    }
                                                }
                                            }
                                            else if (line.StartsWith("msgstr") && line.Length >= 9)
                                            {
                                                Match matchTranslated = rgxTranslatedString.Match(line);
                                                if (matchTranslated.Success && matchTranslated.Groups[1].Length == 0)
                                                { // line is msgstr "" -  multiline string, move to the next line to start reading
                                                    StringBuilder multiLine = new StringBuilder();
                                                    for (j = i + 1; j < lines.Length; j++)
                                                    {
                                                        string nextLine = lines[j].Trim();
                                                        if (nextLine.Length < 2 || nextLine[0] != '"')
                                                        { // either an unexpected char or anything but a quote means the end of the multi-line string
                                                            break;
                                                        }
                                                        else if (line.Length > 3)
                                                        { // A line could contain just "", but it should be skipped if so
                                                            multiLine.Append(nextLine.Substring(1, nextLine.Length - 2));
                                                        }
                                                    }
                                                    if (multiLine.Length > 0)
                                                    {
                                                        data.TranslatedString = multiLine.ToString();
                                                        i = j - 1;
                                                    }
                                                }
                                                else if (line.Length >= 10)
                                                { // Must be at least msgstr "x"
                                                    Match matchTranslatedPlural = rgxTranslatedPlural.Match(line);
                                                    if (matchTranslatedPlural.Success)
                                                    {
                                                        if (data.TranslatedPlurals == null)
                                                        {
                                                            data.TranslatedPlurals = new Dictionary<int, Dictionary<string, string>>();
                                                        }
                                                        data.TranslatedPlurals.Add(int.Parse(matchTranslatedPlural.Groups[1].Value), new Dictionary<string, string>() { { language, matchTranslatedPlural.Groups[2].Value } });
                                                    }
                                                    else
                                                    {
                                                        data.TranslatedString = matchTranslated.Groups[1].Value;
                                                    }
                                                }
                                            }
                                            else if (line.StartsWith("msgctxt") && line.Length >= 10)
                                            {
                                                Match matchContext = rgxContext.Match(line);
                                                data.Context = matchContext.Groups[1].Value;
                                            }
                                        }
                                        break;
                                }
                            }
                        }
                        if (translatorComments != null)
                        {
                            data.TranslatorsComments.Add(language, translatorComments.ToString());
                        }
                        string msgIdHash = Utils.MD5(data.UntranslatedString);
                        if (data.TranslatedPlurals != null)
                        {
                            data.TranslatedString = data.TranslatedPlurals[0][language].ToString(); // the singular form
                        }
                        if (!bundles[bundleName].ContainsKey(msgIdHash))
                        { // first entry in  this bundle
                            bundles[bundleName].Add(msgIdHash, new Dictionary<string, string>());
                            elementData[bundleName].Add(msgIdHash, data);
                        }
                        else
                        { // the meta data has already been added, append the plural and comment meta data from this entry to the existing data
                            if (data.TranslatedPlurals != null)
                            {
                                foreach (KeyValuePair<int, Dictionary<string, string>> plural in data.TranslatedPlurals)
                                {
                                    if (!elementData[bundleName][msgIdHash].TranslatedPlurals.ContainsKey(plural.Key))
                                    {
                                        elementData[bundleName][msgIdHash].TranslatedPlurals.Add(plural.Key, new Dictionary<string, string>());
                                    }
                                    elementData[bundleName][msgIdHash].TranslatedPlurals[plural.Key].Add(language, plural.Value[language]);
                                }
                            }
                            if (data.TranslatorsComments.Count > 0)
                            {
                                foreach (KeyValuePair<string, string> comment in data.TranslatorsComments)
                                {
                                    if (!elementData[bundleName][msgIdHash].TranslatorsComments.ContainsKey(comment.Key))
                                    { // no translator comments in this language
                                        elementData[bundleName][msgIdHash].TranslatorsComments.Add(comment.Key, comment.Value);
                                    }
                                    else
                                    {
                                        elementData[bundleName][msgIdHash].TranslatorsComments[comment.Key] = comment.Value;
                                    }
                                }
                            }
                        }
                        if (data.TranslatedString.Length > 0 && !bundles[bundleName][msgIdHash].ContainsKey(language))
                        {
                            bundles[bundleName][msgIdHash].Add(language, data.TranslatedString);
                        }
                    }
                    catch (Exception ex)
                    {
                        log(new StatusMessage(string.Format(I18nUtils.GetString("Errors", "ErrorParsingDesc"), entry, ex.Message), StatusMessage.StatusMessageType.Error));
                    }
                }
            }

            log(new StatusMessage(I18nUtils.GetString("UIStrings", "ParseDoneStartingImport"), StatusMessage.StatusMessageType.Success));

            Database db = null;
            try
            {
                if (db == null || !db.Connected)
                {
                    db = new Database();
                    db.OpenConnection();
                }
                using (DbTransaction trans = db.BeginTransaction())
                {
                    int numBundles = 0,
                        numElements = 0,
                        numResources = 0;
                    using (Command cmd = db.CreateCommand(trans))
                    using (Command cmdInsertBundle = db.CreateCommand(trans))
                    using (Command cmdCheckExisting = db.CreateCommand(trans))
                    using (Command cmdInsertElement = db.CreateCommand(trans))
                    using (Command cmdUpdateElement = db.CreateCommand(trans))
                    using (Command cmdFindSimilar = db.CreateCommand(trans))
                    using (Command cmdInsertResource = db.CreateCommand(trans))
                    using (Command cmdMaxRow = db.CreateCommand(trans))
                    {
                        Hashtable appBundles = new Hashtable(); // <bundlename, bundleid>
                        cmd.CommandText = "SELECT name, id FROM " + db.TablePrefix + "bundles WHERE application = @id";
                        cmd.AddParameterWithValue("@id", application.ID);
                        DbDataReader reader = cmd.ExecuteReader();
                        while (reader.Read())
                        {
                            appBundles.Add(reader[0], reader[1]);
                        }
                        reader.Close();

                        cmdInsertBundle.CommandText = "INSERT INTO " + db.TablePrefix + "bundles (id, name, application) VALUES (@id, @name, @application)";
                        cmdInsertBundle.AddParameterWithValue("@id", "");
                        cmdInsertBundle.AddParameterWithValue("@name", "");
                        cmdInsertBundle.AddParameterWithValue("@application", application.ID);

                        cmdCheckExisting.CommandText = "SELECT resourceid FROM " + db.TablePrefix + "elements WHERE applicationid = @appId AND bundle = @bundle AND elementname = @element";
                        cmdCheckExisting.AddParameterWithValue("@appId", application.ID);
                        cmdCheckExisting.AddParameterWithValue("@bundle", "");
                        cmdCheckExisting.AddParameterWithValue("@element", "");

                        cmdInsertElement.CommandText = "INSERT INTO " + db.TablePrefix + "elements (applicationid, bundle, elementname, resourceid, comment) VALUES (@appId, @bundle, @element, @tId, @metaData)";
                        cmdInsertElement.AddParameterWithValue("@appId", application.ID);
                        cmdInsertElement.AddParameterWithValue("@bundle", "");
                        cmdInsertElement.AddParameterWithValue("@element", "");
                        cmdInsertElement.AddParameterWithValue("@tId", "");
                        cmdInsertElement.AddParameterWithValue("@metaData", "");

                        cmdUpdateElement.CommandText = "UPDATE " + db.TablePrefix + "elements SET comment = @metaData WHERE applicationid = @appId AND bundle = @bundle AND elementname = @element";
                        cmdUpdateElement.AddParameterWithValue("@appId", application.ID);
                        cmdUpdateElement.AddParameterWithValue("@bundle", "");
                        cmdUpdateElement.AddParameterWithValue("@element", "");
                        cmdUpdateElement.AddParameterWithValue("@metaData", "");

                        cmdFindSimilar.CommandText = "SELECT resourceid FROM " + db.TablePrefix + "resources WHERE language = @language AND translation = @translation";
                        cmdFindSimilar.AddParameterWithValue("@language", application.DefaultLanguage); // Only match if the default language for this app. is present in the uploaded resources
                        cmdFindSimilar.AddParameterWithValue("@translation", "");

                        switch (db.InstanceType)
                        {
                            case DatabaseType.MySQL:
                                cmdInsertResource.CommandText = "INSERT INTO " + db.TablePrefix + "resources (resourceid, language, translation, translatorcomment) VALUES (@tId, @language, @translation, @comment) ON DUPLICATE KEY UPDATE translation = @translation, translatorcomment = @comment";
                                break;
                            case DatabaseType.SQLServer:
                                cmdInsertResource.CommandText = "UPDATE " + db.TablePrefix + "resources SET translation = @translation, translatorcomment = @comment WHERE resourceid = @tId AND language = @language; IF @@ROWCOUNT = 0 INSERT INTO " + db.TablePrefix + "resources (resourceid, language, translation, translatorcomment) VALUES (@tId, @language, @translation, @comment)";
                                break;
                            case DatabaseType.SQLite:
                                cmdInsertResource.CommandText = "INSERT OR REPLACE INTO " + db.TablePrefix + "resources (resourceid, language, translation, translatorcomment) VALUES (@tId, @language, @translation, @comment)";
                                break;
                        }
                        cmdInsertResource.AddParameterWithValue("@tID", "");
                        cmdInsertResource.AddParameterWithValue("@language", "");
                        cmdInsertResource.AddParameterWithValue("@translation", "");
                        cmdInsertResource.AddParameterWithValue("@comment", "");

                        cmdMaxRow.CommandText = "SELECT MAX(resourceid) FROM " + db.TablePrefix + "resources";

                        int resourceId = 0;
                        string bundleId;
                        foreach (KeyValuePair<string, Dictionary<string, Dictionary<string, string>>> bundle in bundles)
                        { // <bundle, <msgId, <language, translation>>>
                            log(new StatusMessage(string.Format(I18nUtils.GetString("UIStrings", "ImportingBundleName"), bundle.Key), StatusMessage.StatusMessageType.Status));
                            bundleName = bundle.Key;
                            if (appBundles.ContainsKey(bundleName))
                            {
                                bundleId = appBundles[bundleName].ToString();
                            }
                            else
                            {
                                bundleId = Utils.GenID(true);
                                cmdInsertBundle.Parameters["@id"].Value = bundleId;
                                cmdInsertBundle.Parameters["@name"].Value = bundle.Key;
                                cmdInsertBundle.ExecuteNonQuery();
                                appBundles.Add(bundleName, bundleId);
                            }
                            cmdCheckExisting.Parameters["@bundle"].Value = bundleId;
                            cmdInsertElement.Parameters["@bundle"].Value = bundleId;
                            string elementName; // the first reference for the entry
                            POMetaData thisElementData;
                            foreach (KeyValuePair<string, Dictionary<string, string>> entry in bundle.Value)
                            { // <msgId, <language, translation>>
                                numElements++;
                                thisElementData = elementData[bundleName][entry.Key];
                                string elementContext = thisElementData.Context == null ? "" : "-" + thisElementData.Context;
                                string msgIdSnippet;
                                if (thisElementData.UntranslatedString == "")
                                {
                                    elementName = "Generator";
                                }
                                else
                                {
                                    if (thisElementData.UntranslatedString.Length > 0)
                                    {
                                        msgIdSnippet = thisElementData.UntranslatedString.Substring(0, thisElementData.UntranslatedString.Length > 10 ? 10 : thisElementData.UntranslatedString.Length); // truncate to 10 chars
                                    }
                                    else if (thisElementData.TranslatedString.Length > 0)
                                    {
                                        msgIdSnippet = thisElementData.TranslatedString.Substring(0, thisElementData.TranslatedString.Length > 10 ? 10 : thisElementData.TranslatedString.Length); // truncate to 10 chars
                                    }
                                    else
                                    {
                                        msgIdSnippet = I18nUtils.GetString("UIStrings", "Unnamed") + entry.Key.Substring(0, 10);
                                    }
                                    if (thisElementData.References.Count > 0)
                                    {
                                        string elementReference = elementData[bundleName][entry.Key].References[0]; // use the first reference to generate part of the element name
                                        int slashPos = elementReference.LastIndexOf('/'),
                                            colonPos = elementReference.LastIndexOf(':');
                                        if (slashPos >= 0)
                                        { // directory included
                                            if (colonPos > 1)
                                            {
                                                elementName = (elementReference.Substring(slashPos + 1, colonPos - slashPos - 1) + thisElementData.Context + "-" + msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                            }
                                            else
                                            {
                                                elementName = (elementReference.Substring(slashPos + 1) + thisElementData.Context + "-" + msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                            }
                                        }
                                        else
                                        { // no directory
                                            if (colonPos > 1)
                                            {
                                                elementName = (elementReference.Substring(0, colonPos) + thisElementData.Context + "-" + msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                            }
                                            else
                                            {
                                                elementName = (elementReference + thisElementData.Context + "-" + msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                            }
                                        }
                                    }
                                    else if (thisElementData.Context != null)
                                    {
                                        elementName = (thisElementData.Context + "-" + msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                    }
                                    else
                                    {
                                        elementName = (msgIdSnippet + "-" + entry.Key.Substring(0, 4)).Replace(" ", "");
                                    }
                                }
                                cmdCheckExisting.Parameters["@element"].Value = elementName;
                                reader = cmdCheckExisting.ExecuteReader();
                                if (reader.HasRows)
                                { // the element already exists, overwrite existing languages with the ones from the bundle
                                    reader.Read();
                                    int.TryParse(reader[0].ToString(), out resourceId);
                                    reader.Close();
                                    cmdUpdateElement.Parameters["@metaData"].Value = elementData[bundleName][entry.Key].ToCommentsField();
                                }
                                else
                                { // no matching elements, create one first
                                    reader.Close();
                                    cmdInsertElement.Parameters["@element"].Value = elementName;
                                    cmdInsertElement.Parameters["@metaData"].Value = elementData[bundleName][entry.Key].ToCommentsField();
                                    // check for other resources which might be have the same translation, then append the translations in this bundle to them instead of creating a duplicate resource. 
                                    bool readId = false;
                                    if (entry.Value.ContainsKey(application.DefaultLanguage))
                                    {
                                        cmdFindSimilar.Parameters["@translation"].Value = entry.Value[application.DefaultLanguage];
                                        reader = cmdFindSimilar.ExecuteReader();
                                        if (reader.HasRows)
                                        { // translation of current element matches one already in the database, use the existing resource ID
                                            reader.Read();
                                            resourceId = reader.GetInt32(0);
                                            readId = true;
                                        }
                                        reader.Close();
                                    }
                                    if (!readId)
                                    { // no matching resources, find the next available resource ID
                                        using (DbDataReader maxIdReader = cmdMaxRow.ExecuteReader(CommandBehavior.SingleRow))
                                        {
                                            if (maxIdReader.HasRows)
                                            {
                                                maxIdReader.Read();
                                                int.TryParse(maxIdReader[0].ToString(), out resourceId);
                                                resourceId++;
                                            }
                                            maxIdReader.Close();
                                        }
                                    }
                                    cmdInsertElement.Parameters["@tId"].Value = resourceId;
                                    cmdInsertElement.ExecuteNonQuery();
                                }

                                cmdInsertResource.Parameters["@tId"].Value = resourceId;
                                foreach (KeyValuePair<string, string> resource in entry.Value)
                                { // <language, translation>>
                                    cmdInsertResource.Parameters["@language"].Value = resource.Key;
                                    cmdInsertResource.Parameters["@translation"].Value = resource.Value;
                                    if (thisElementData.TranslatorsComments.ContainsKey(resource.Key))
                                    {
                                        cmdInsertResource.Parameters["@comment"].Value = thisElementData.TranslatorsComments[resource.Key];
                                    }
                                    else
                                    {
                                        cmdInsertResource.Parameters["@comment"].Value = DBNull.Value;
                                    }
                                    try
                                    {
                                        cmdInsertResource.ExecuteNonQuery();
                                        numResources++;
                                    }
                                    catch (Exception ex)
                                    {
                                        log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                                    }
                                }
                                if (!entry.Value.ContainsKey(application.DefaultLanguage) && thisElementData.UntranslatedString.Length > 0)
                                { // the default language hasn't been added, use the untranslated string (msgid) from the PO file
                                    cmdInsertResource.Parameters["@language"].Value = application.DefaultLanguage;
                                    cmdInsertResource.Parameters["@translation"].Value = thisElementData.UntranslatedString;
                                    try
                                    {
                                        cmdInsertResource.ExecuteNonQuery();
                                        numResources++;
                                    }
                                    catch (Exception ex)
                                    {
                                        log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                                    }
                                }

                                if (thisElementData.TranslatedPlurals != null)
                                {
                                    foreach (KeyValuePair<int, Dictionary<string, string>> plural in thisElementData.TranslatedPlurals)
                                    {
                                        if (plural.Key == 0)
                                        {
                                            continue;
                                        }
                                        string pluralName = elementName + "_" + plural.Key;
                                        cmdCheckExisting.Parameters["@element"].Value = pluralName;
                                        cmdInsertElement.Parameters["@element"].Value = pluralName;
                                        reader = cmdCheckExisting.ExecuteReader();
                                        if (reader.HasRows)
                                        { // the element already exists, overwrite existing languages with the ones from the bundle
                                            reader.Read();
                                            int.TryParse(reader[0].ToString(), out resourceId);
                                        }// can't check for similar because the PO format only supports one untranslated plural, so translated plural 2 would overwrite it
                                        reader.Close();
                                        using (DbDataReader maxIdReader = cmdMaxRow.ExecuteReader(CommandBehavior.SingleRow))
                                        {
                                            if (maxIdReader.HasRows)
                                            {
                                                maxIdReader.Read();
                                                int.TryParse(maxIdReader[0].ToString(), out resourceId);
                                                resourceId++;
                                            }
                                            maxIdReader.Close();
                                        }
                                        cmdInsertResource.Parameters["@tId"].Value = resourceId;
                                        cmdInsertElement.Parameters["@tId"].Value = resourceId;
                                        try
                                        {
                                            cmdInsertElement.ExecuteNonQuery();
                                        }
                                        catch (Exception ex)
                                        {
                                            log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                                        }

                                        if (!plural.Value.ContainsKey(application.DefaultLanguage))
                                        {
                                            cmdInsertResource.Parameters["@language"].Value = application.DefaultLanguage;
                                            cmdInsertResource.Parameters["@translation"].Value = thisElementData.UntranslatedPlural;
                                            try
                                            {
                                                cmdInsertResource.ExecuteNonQuery();
                                                numResources++;
                                            }
                                            catch (Exception ex)
                                            {
                                                log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                                            }
                                        }

                                        foreach (KeyValuePair<string, string> translatedPlural in plural.Value)
                                        { // <language, plural>>
                                            cmdInsertResource.Parameters["@language"].Value = translatedPlural.Key;
                                            cmdInsertResource.Parameters["@translation"].Value = translatedPlural.Value;
                                            try
                                            {
                                                cmdInsertResource.ExecuteNonQuery();
                                                numResources++;
                                            }
                                            catch (Exception ex)
                                            {
                                                log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
                                            }
                                        }
                                    }
                                }
                            }
                            numBundles++;
                        }
                        if (newLanguages.Count > 0)
                        {
                            application.Languages.AddRange(newLanguages);
                            cmd.CommandText = string.Format("UPDATE {0}applications SET languages = @langs WHERE id = @applicationId", db.TablePrefix);
                            cmd.AddParameterWithValue("@langs", Utils.Implode(application.Languages, ",", true));
                            cmd.AddParameterWithValue("@applicationId", application.ID);
                            cmd.ExecuteNonQuery();
                            log(new StatusMessage(string.Format(I18nUtils.GetString("UIStrings", "AddedNumNewLanguages"), newLanguages.Count), StatusMessage.StatusMessageType.Success));//UIStrings.AddedNumNewLanguages
                        }
                    }
                    log(new StatusMessage(string.Format(I18nUtils.GetString("UIStrings", "ImportSummaryDesc"), numResources, numBundles, numElements), StatusMessage.StatusMessageType.Success));
                    trans.Commit();
                }
            }
            catch (Exception ex)
            {
                log(new StatusMessage(ex.Message, StatusMessage.StatusMessageType.Error));
            }
            finally
            {
                if (db != null && db.Connected)
                {
                    try
                    {
                        db.CloseConnection();
                    }
                    catch { }
                }
            }
        }
    
    }
}
